package com.cencat.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cencat.common.utils.PaginationHelper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cencat.common.response.PageResponse;
import org.springframework.util.StringUtils;
import com.cencat.common.enums.ErrorCode;
import com.cencat.common.exception.BusinessException;
import com.cencat.user.config.CacheConfig;
import com.cencat.user.dto.RoleCreateDTO;
import com.cencat.user.dto.RoleQueryDTO;
import com.cencat.user.dto.RoleUpdateDTO;
import com.cencat.user.entity.Role;
import com.cencat.user.entity.UserRole;
import com.cencat.user.mapper.RoleMapper;
import com.cencat.user.mapper.UserRoleMapper;
import com.cencat.user.service.RoleService;
import com.cencat.user.vo.RoleListVO;
import com.cencat.user.vo.RoleVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import com.cencat.common.utils.CencatStringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 角色服务实现类
 * @author cencat
 * @since 2024-01-01
 */
@Service
@Slf4j
public class RoleServiceImpl implements RoleService {

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "rolePage", allEntries = true)
    public Long createRole(RoleCreateDTO dto) throws BusinessException {
        log.info("开始创建角色: roleName={}, roleCode={}", dto.getRoleName(), dto.getRoleCode());
        
        // 参数校验
        if (dto == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        // 检查角色编码是否存在
        if (checkRoleCodeExists(dto.getRoleCode(), null, dto.getTenantId())) {
            throw new BusinessException(ErrorCode.ROLE_CODE_EXISTS);
        }
        
        // 检查角色名称是否存在
        if (checkRoleNameExists(dto.getRoleName(), null, dto.getTenantId())) {
            throw new BusinessException(ErrorCode.ROLE_NAME_EXISTS);
        }
        
        try {
            // 创建角色实体
            Role role = new Role();
            BeanUtils.copyProperties(dto, role);
            role.setStatus(Role.Status.NORMAL.getCode());
            role.setCreateTime(LocalDateTime.now());
            role.setUpdateTime(LocalDateTime.now());
            
            int result = roleMapper.insert(role);
            if (result <= 0) {
                throw new BusinessException(ErrorCode.OPERATION_FAILED);
            }
            
            log.info("角色创建成功: roleId={}, roleName={}", role.getId(), dto.getRoleName());
            return role.getId();
        } catch (BusinessException e) {
            log.error("角色创建失败: roleName={}, error={}", dto.getRoleName(), e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("角色创建异常: roleName={}, error={}", dto.getRoleName(), e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"rolePage", "roleDetail"}, allEntries = true)
    public Boolean updateRole(RoleUpdateDTO dto) throws BusinessException {
        log.info("开始更新角色: roleId={}, roleName={}", dto.getId(), dto.getRoleName());
        
        // 参数校验
        if (dto == null || dto.getId() == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        // 检查角色是否存在
        Role existingRole = roleMapper.selectById(dto.getId());
        if (existingRole == null || existingRole.getDeleted() == 1) {
            throw new BusinessException(ErrorCode.ROLE_NOT_EXISTS);
        }
        
        // 检查角色编码是否存在（排除当前角色）
        if (CencatStringUtils.isNotBlank(dto.getRoleCode()) && 
            checkRoleCodeExists(dto.getRoleCode(), dto.getId(), dto.getTenantId())) {
            throw new BusinessException(ErrorCode.ROLE_CODE_EXISTS);
        }
        
        // 检查角色名称是否存在（排除当前角色）
        if (CencatStringUtils.isNotBlank(dto.getRoleName()) && 
            checkRoleNameExists(dto.getRoleName(), dto.getId(), dto.getTenantId())) {
            throw new BusinessException(ErrorCode.ROLE_NAME_EXISTS);
        }
        
        try {
            // 更新角色信息
            Role role = new Role();
            BeanUtils.copyProperties(dto, role);
            role.setUpdateTime(LocalDateTime.now());
            
            int result = roleMapper.updateById(role);
            if (result <= 0) {
                throw new BusinessException(ErrorCode.OPERATION_FAILED);
            }
            
            log.info("角色更新成功: roleId={}, roleName={}", dto.getId(), dto.getRoleName());
            return true;
        } catch (BusinessException e) {
            log.error("角色更新失败: roleId={}, error={}", dto.getId(), e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("角色更新异常: roleId={}, error={}", dto.getId(), e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = {"rolePage", "roleDetail", "userRolePage", "rolePermissionPage"}, allEntries = true)
    public Boolean deleteRole(Long roleId, Long tenantId) throws BusinessException {
        log.info("开始删除角色: roleId={}, tenantId={}", roleId, tenantId);
        
        // 参数校验
        if (roleId == null || tenantId == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        // 检查角色是否存在
        Role existingRole = roleMapper.selectById(roleId);
        if (existingRole == null || existingRole.getDeleted() == 1) {
            throw new BusinessException(ErrorCode.ROLE_NOT_EXISTS);
        }
        
        // 检查是否有用户关联此角色
        LambdaQueryWrapper<UserRole> userRoleQuery = new LambdaQueryWrapper<>();
        userRoleQuery.eq(UserRole::getRoleId, roleId)
                    .eq(UserRole::getTenantId, tenantId)
                    .eq(UserRole::getDeleted, 0);
        Long userRoleCount = userRoleMapper.selectCount(userRoleQuery);
        if (userRoleCount > 0) {
            throw new BusinessException(ErrorCode.ROLE_HAS_USERS);
        }
        
        try {
            // 逻辑删除角色
            LambdaUpdateWrapper<Role> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Role::getId, roleId)
                        .eq(Role::getTenantId, tenantId)
                        .set(Role::getDeleted, 1)
                        .set(Role::getUpdateTime, LocalDateTime.now());
            
            int result = roleMapper.update(null, updateWrapper);
            if (result <= 0) {
                throw new BusinessException(ErrorCode.OPERATION_FAILED);
            }
            
            log.info("角色删除成功: roleId={}", roleId);
            return true;
        } catch (BusinessException e) {
            log.error("角色删除失败: roleId={}, error={}", roleId, e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("角色删除异常: roleId={}, error={}", roleId, e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchDeleteRoles(List<Long> roleIds, Long tenantId) throws BusinessException {
        log.info("开始批量删除角色: roleIds={}, tenantId={}", roleIds, tenantId);
        
        // 参数校验
        if (CollectionUtils.isEmpty(roleIds) || tenantId == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        try {
            for (Long roleId : roleIds) {
                deleteRole(roleId, tenantId);
            }
            
            log.info("批量删除角色成功: roleIds={}", roleIds);
            return true;
        } catch (BusinessException e) {
            log.error("批量删除角色失败: roleIds={}, error={}", roleIds, e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("批量删除角色异常: roleIds={}, error={}", roleIds, e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    @Override
    public RoleVO getRoleById(Long roleId, Long tenantId) throws BusinessException {
        // 参数校验
        if (roleId == null || tenantId == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        try {
            Role role = roleMapper.selectById(roleId);
            if (role == null || role.getDeleted() == 1 || !role.getTenantId().equals(tenantId)) {
                throw new BusinessException(ErrorCode.ROLE_NOT_EXISTS);
            }
            
            RoleVO roleVO = new RoleVO();
            BeanUtils.copyProperties(role, roleVO);
            return roleVO;
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("查询角色详情异常: roleId={}, error={}", roleId, e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    @Override
    public Role getRoleByCode(String roleCode, Long tenantId) throws BusinessException {
        // 参数校验
        if (CencatStringUtils.isBlank(roleCode) || tenantId == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        try {
            return roleMapper.selectByRoleCode(roleCode, tenantId);
        } catch (Exception e) {
            log.error("根据角色编码查询角色异常: roleCode={}, error={}", roleCode, e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    @Override
    public Role getRoleByName(String roleName, Long tenantId) throws BusinessException {
        // 参数校验
        if (CencatStringUtils.isBlank(roleName) || tenantId == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        try {
            return roleMapper.selectByRoleName(roleName, tenantId);
        } catch (Exception e) {
            log.error("根据角色名称查询角色异常: roleName={}, error={}", roleName, e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    @Override
    @Cacheable(value = "rolePage", 
               key = "T(com.cencat.user.config.CacheConfig.CacheKeyGenerator).generateRolePageKey(#queryDTO.tenantId, #queryDTO.pageNum, #queryDTO.pageSize, #queryDTO.roleName, #queryDTO.status)",
               condition = "#queryDTO != null and #queryDTO.tenantId != null")
    public PageResponse<RoleListVO> getRolePage(RoleQueryDTO queryDTO) throws BusinessException {
        // 参数校验
        if (queryDTO == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        try {
            // 构建分页查询参数
            PaginationHelper.PageQuery pageQuery = new PaginationHelper.PageQuery();
            if (queryDTO.getPageNum() != null) {
                pageQuery.setCurrent(queryDTO.getPageNum().longValue());
            }
            if (queryDTO.getPageSize() != null) {
                pageQuery.setSize(queryDTO.getPageSize().longValue());
            }
            
            // 构建查询条件
            QueryWrapper<Role> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("tenant_id", queryDTO.getTenantId());
            
            if (StringUtils.hasText(queryDTO.getRoleName())) {
                queryWrapper.like("role_name", queryDTO.getRoleName());
            }
            
            if (queryDTO.getStatus() != null) {
                queryWrapper.eq("status", queryDTO.getStatus());
            }
            
            queryWrapper.eq("is_deleted", 0);
            queryWrapper.orderByDesc("create_time");
            
            // 执行分页查询并转换为VO
            return PaginationHelper.executePage(roleMapper, pageQuery, queryWrapper, this::convertToListVO);
        } catch (Exception e) {
            log.error("分页查询角色列表异常: error={}", e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    @Override
    public List<RoleListVO> getRoleList(RoleQueryDTO queryDTO) throws BusinessException {
        // 参数校验
        if (queryDTO == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        try {
            List<Role> roleList = roleMapper.selectRoleList(queryDTO);
            
            return roleList.stream()
                    .map(role -> {
                        RoleListVO roleVO = new RoleListVO();
                        BeanUtils.copyProperties(role, roleVO);
                        return roleVO;
                    })
                    .collect(Collectors.toList());
        } catch (Exception e) {
            log.error("查询角色列表异常: error={}", e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean enableRole(Long roleId, Long tenantId, Long operatorId) throws BusinessException {
        return updateRoleStatus(roleId, Role.Status.NORMAL.getCode(), tenantId, operatorId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean disableRole(Long roleId, Long tenantId, Long operatorId) throws BusinessException {
        return updateRoleStatus(roleId, Role.Status.DISABLED.getCode(), tenantId, operatorId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchUpdateRoleStatus(List<Long> roleIds, Integer status, Long tenantId, Long operatorId) throws BusinessException {
        // 参数校验
        if (CollectionUtils.isEmpty(roleIds) || status == null || tenantId == null || operatorId == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        try {
            for (Long roleId : roleIds) {
                updateRoleStatus(roleId, status, tenantId, operatorId);
            }
            
            log.info("批量更新角色状态成功: roleIds={}, status={}", roleIds, status);
            return true;
        } catch (BusinessException e) {
            log.error("批量更新角色状态失败: roleIds={}, status={}, error={}", roleIds, status, e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("批量更新角色状态异常: roleIds={}, status={}, error={}", roleIds, status, e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    @Override
    public List<Role> getRolesByUserId(Long userId, Long tenantId) throws BusinessException {
        // 参数校验
        if (userId == null || tenantId == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        try {
            return roleMapper.selectRolesByUserId(userId, tenantId);
        } catch (Exception e) {
            log.error("根据用户ID查询角色列表异常: userId={}, error={}", userId, e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    @Override
    public List<Role> getRolesByTenantId(Long tenantId) throws BusinessException {
        // 参数校验
        if (tenantId == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        try {
            return roleMapper.selectRolesByTenantId(tenantId);
        } catch (Exception e) {
            log.error("根据租户ID查询角色列表异常: tenantId={}, error={}", tenantId, e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    @Override
    public Long countRoles(RoleQueryDTO queryDTO) throws BusinessException {
        // 参数校验
        if (queryDTO == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        try {
            return roleMapper.countRoles(queryDTO);
        } catch (Exception e) {
            log.error("统计角色数量异常: error={}", e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    @Override
    public Boolean checkRoleCodeExists(String roleCode, Long excludeRoleId, Long tenantId) throws BusinessException {
        // 参数校验
        if (CencatStringUtils.isBlank(roleCode) || tenantId == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        try {
            Long count = roleMapper.checkRoleCodeExists(roleCode, excludeRoleId, tenantId);
            return count > 0;
        } catch (Exception e) {
            log.error("检查角色编码是否存在异常: roleCode={}, error={}", roleCode, e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    @Override
    public Boolean checkRoleNameExists(String roleName, Long excludeRoleId, Long tenantId) throws BusinessException {
        // 参数校验
        if (CencatStringUtils.isBlank(roleName) || tenantId == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        try {
            Long count = roleMapper.checkRoleNameExists(roleName, excludeRoleId, tenantId);
            return count > 0;
        } catch (Exception e) {
            log.error("检查角色名称是否存在异常: roleName={}, error={}", roleName, e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean assignRolesToUser(Long userId, List<Long> roleIds, Long tenantId, Long operatorId) throws BusinessException {
        // 参数校验
        if (userId == null || CollectionUtils.isEmpty(roleIds) || tenantId == null || operatorId == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        try {
            // 先删除用户现有角色关联
            LambdaUpdateWrapper<UserRole> deleteWrapper = new LambdaUpdateWrapper<>();
            deleteWrapper.eq(UserRole::getUserId, userId)
                        .eq(UserRole::getTenantId, tenantId)
                        .set(UserRole::getDeleted, 1)
                        .set(UserRole::getUpdateTime, LocalDateTime.now());
            userRoleMapper.update(null, deleteWrapper);
            
            // 添加新的角色关联
            List<UserRole> userRoleList = new ArrayList<>();
            for (Long roleId : roleIds) {
                UserRole userRole = new UserRole();
                userRole.setUserId(userId);
                userRole.setRoleId(roleId);
                userRole.setTenantId(tenantId);
                userRole.setCreateBy(operatorId);
                userRole.setCreateTime(LocalDateTime.now());
                userRole.setUpdateTime(LocalDateTime.now());
                userRoleList.add(userRole);
            }
            
            // 批量插入用户角色关联
            for (UserRole userRole : userRoleList) {
                userRoleMapper.insert(userRole);
            }
            
            log.info("为用户分配角色成功: userId={}, roleIds={}", userId, roleIds);
            return true;
        } catch (Exception e) {
            log.error("为用户分配角色异常: userId={}, roleIds={}, error={}", userId, roleIds, e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean removeRolesFromUser(Long userId, List<Long> roleIds, Long tenantId, Long operatorId) throws BusinessException {
        // 参数校验
        if (userId == null || CollectionUtils.isEmpty(roleIds) || tenantId == null || operatorId == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        try {
            // 删除指定的用户角色关联
            LambdaUpdateWrapper<UserRole> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(UserRole::getUserId, userId)
                        .eq(UserRole::getTenantId, tenantId)
                        .in(UserRole::getRoleId, roleIds)
                        .set(UserRole::getDeleted, 1)
                        .set(UserRole::getUpdateTime, LocalDateTime.now())
                        .set(UserRole::getUpdateBy, operatorId);
            
            int result = userRoleMapper.update(null, updateWrapper);
            if (result <= 0) {
                throw new BusinessException(ErrorCode.OPERATION_FAILED);
            }
            
            log.info("移除用户角色成功: userId={}, roleIds={}", userId, roleIds);
            return true;
        } catch (BusinessException e) {
            log.error("移除用户角色失败: userId={}, roleIds={}, error={}", userId, roleIds, e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("移除用户角色异常: userId={}, roleIds={}, error={}", userId, roleIds, e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    /**
     * 更新角色状态
     * @param roleId 角色ID
     * @param status 状态
     * @param tenantId 租户ID
     * @param operatorId 操作人ID
     * @return 是否成功
     */
    private Boolean updateRoleStatus(Long roleId, Integer status, Long tenantId, Long operatorId) throws BusinessException {
        // 参数校验
        if (roleId == null || status == null || tenantId == null || operatorId == null) {
            throw new BusinessException(ErrorCode.PARAM_ERROR);
        }
        
        // 检查角色是否存在
        Role existingRole = roleMapper.selectById(roleId);
        if (existingRole == null || existingRole.getDeleted() == 1 || !existingRole.getTenantId().equals(tenantId)) {
            throw new BusinessException(ErrorCode.ROLE_NOT_EXISTS);
        }
        
        try {
            LambdaUpdateWrapper<Role> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Role::getId, roleId)
                        .eq(Role::getTenantId, tenantId)
                        .set(Role::getStatus, status)
                        .set(Role::getUpdateTime, LocalDateTime.now())
                        .set(Role::getUpdateBy, operatorId);
            
            int result = roleMapper.update(null, updateWrapper);
            if (result <= 0) {
                throw new BusinessException(ErrorCode.OPERATION_FAILED);
            }
            
            log.info("更新角色状态成功: roleId={}, status={}", roleId, status);
            return true;
        } catch (BusinessException e) {
            log.error("更新角色状态失败: roleId={}, status={}, error={}", roleId, status, e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("更新角色状态异常: roleId={}, status={}, error={}", roleId, status, e.getMessage(), e);
            throw new BusinessException(ErrorCode.OPERATION_FAILED);
        }
    }

    /**
     * 将Role实体转换为RoleListVO
     * @param role Role实体
     * @return RoleListVO
     */
    private RoleListVO convertToListVO(Role role) {
        RoleListVO roleListVO = new RoleListVO();
        BeanUtils.copyProperties(role, roleListVO);
        return roleListVO;
    }
}